#ifndef _PROJECT_H_
#define _PROJECT_H_
#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;

#ifdef __cplusplus
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <sys/ioctl.h>
#include <linux/fb.h> // 定义 fb_var_screeninfo 和 FBIOGET_VSCREENINFO 等
#include "jpeg-arm64/include/jpeglib.h"
#include <pthread.h>

    // 定义结构体，用于返回结果(不管是什么图片的数据最终计算出来的数据放在这里)
    struct ImageLayoutResult
    {
        int draw_width;
        int draw_height;
        int final_x;
        int final_y;
    };

    // bmp图片解码
    struct bitmap_header
    {
        int16_t type;
        int32_t size; // 图像文件大小
        int16_t reserved1;
        int16_t reserved2;
        int32_t offbits; // bmp图像数据偏移量
    } __attribute__((packed));

    struct bitmap_info
    {
        int32_t size;   // 本结构大小
        int32_t width;  // 图像宽
        int32_t height; // 图像高
        int16_t planes;

        int16_t bit_count; // 色深
        int32_t compression;
        int32_t size_img; // BMP中的RGB数据大小，必须是4的整数倍
        int32_t X_pel;
        int32_t Y_pel;
        int32_t clrused;
        int32_t clrImportant;
    } __attribute__((packed));

    // 以下结构体不一定存在于BMP文件中，除非：
    // bitmap_info.compression为真
    struct rgb_quad
    {
        int8_t blue;
        int8_t green;
        int8_t red;
        int8_t reserved;
    } __attribute__((packed));

    // jpg解码
    //  JPEG图片的核心信息结构体
    struct jpeg_info
    {
        const char *filename; // √
        int width;
        int height;
        int bpp;
        int jpg_size; // √
        int rgb_size;

        const unsigned char *jpg_data; // √
        char *rgb_data;
    };

    enum TouchState
    {
        IDLE,       // 无触摸
        TOUCH_DOWN, // 按下中，等待第一个有效坐标
    };

#define START_PATH "/root/image/j6.jpg"
#define END_PATH "/root/image/j7.jpg"
#define NORMAL 1
#define ARRANGE 2
#define smallPC_x 256 // 排列显示时一个照片容器的宽
#define smallPC_y 150 // 排列显示时一个照片容器的高
#define x_Margin 258  // 第一个照片第一个像素到右边照片第一个像素的距离（实际一张照片宽用了252，每张直接隔了6个像素）
#define y_Margin 152  // 第一个照片第一个像素到下面照片第一个像素的距离（实际一张照片宽用了146，每张直接隔了6个像素）

    extern bool is_start;
    extern bool should_exit;
    extern bool is_arrang;
}
#endif
//-------------------------------单例模型-----------------------------------------
// 显示时间
class Timeshow
{
public:
    static class Timeshow &getTime()
    {
        static class Timeshow time;
        return time;
    }
    void init_ascii();

    int show_font(int x, int y, const char *font);
    void show_time();

    char *lcd_mmap_ptr;
    char *A_mmap_ptr;
    int A_size;

private:
    Timeshow() {
        this->init_ascii();
    }
    ~Timeshow() {
        munmap(this->A_mmap_ptr,this->A_size);
    }
    Timeshow(const Timeshow &) = delete;
    void operator=(const Timeshow &) = delete;
};

//-------------------------------观察者模型-----------------------------------------
// 事件类型
// ======================
enum class EventType
{
    TOUCH_CLICK_LEFT_DOWN,
    TOUCH_CLICK_RIGHT_DOWN,
    TOUCH_CLICK_LEFT_UP,
    TOUCH_CLICK_RIGHT_UP,
    TOUCH_SLIDE_LEFT,
    TOUCH_SLIDE_RIGHT,
    TOUCH_CLICK
};
// 观察者类 基类
class Observer
{
public:
    virtual void onEvent(EventType event, int x, int y) = 0;
};

// 被观察者（事件源）
class Subject
{
public:
    virtual void attach(Observer *obs) = 0;
    virtual void detach(Observer *obs) = 0;
    virtual void notify(EventType event, int x, int y) = 0;
};

//-------------------------------工厂模型-----------------------------------------

// 功能类1 (基类产品类)
class ImageDisplay
{
public:
    // 显示照片
    virtual void Showfill_image(const char *image_path) = 0;
};
// 功能类2(基类产品类)
class TouchHandler
{
public:
    // 获取当前事件
    virtual void Get_Touch_Inf() = 0;
};

// 显示照片(派生类产品类)
class Image : public ImageDisplay, public Observer
{
public:
    // 构造函数，接收 LCD 的信息
    Image(int wide, int high, char *ptr, std::vector<std::string> &imagePaths)
        : framebuffer_ptr(ptr),lcd_wide(wide), lcd_high(high), imagePathList(imagePaths), currentIndex(0) {}

    // 观察者成员函数重写
    void onEvent(EventType event, int x, int y) override;
    int get_image_index_by_pos(int x, int y);

    void Show_image(const char *image_path, int mode = NORMAL, int n = 0);
    void Show_bmp(const char *image_path, int mode = NORMAL, int n = 0);
    void Show_jpg(const char *image_path, int mode = NORMAL, int n = 0);
    void load_jpg(const char *jpgname, struct jpeg_info *p);
    struct jpeg_info *jpg2rgb(const char *jpgfile);
    static ImageLayoutResult GetDisplayLayout(int image_width, int image_height,
                                              int target_area_x, int target_area_y,
                                              int target_area_w, int target_area_h);
    void Showfill_image(const char *image_path) override;
    void Show_arrang();

    char *framebuffer_ptr; // 映射的帧缓冲区指针
private:
    int lcd_wide; // LCD 宽度
    int lcd_high; // LCD 高度

    std::vector<std::string> imagePathList;
    int currentIndex;
};

// 获取触摸(派生类产品类)
class Get_touch : public TouchHandler, public Subject
{
public:
    Get_touch(int dev_fd) : dev_fd(dev_fd), has_set_start(false)
    {
    }
    void Get_Touch_Inf() override;
    void analyzeTouchEvent();

    // 重写被观察者类成员函数
    void attach(Observer *obs) override
    {
        this->observers.push_back(obs);
    }
    void detach(Observer *obs) override
    {
        auto it = this->observers.begin();
        for (; it != this->observers.end(); it++)
        {
            if (*it == obs)
            {
                break;
            }
        }
        this->observers.erase(it);
    }
    void notify(EventType event, int x = 0, int y = 0) override
    {
        for (auto obs : observers)
        {                              // 把存放 观察者容器 换成  一个基类指针即可
            obs->onEvent(event, x, y); // 观察者获取 被观察的消息
        }
    }

private:
    int dev_fd;
    int current_x;
    int current_y;
    int start_x;
    int start_y;
    int end_x;
    int end_y;
    bool has_set_start = false;
    TouchState state;
    std::vector<Observer *> observers;
};

// 基础设备类(基类工厂类)
class DEVICE
{
public:
    DEVICE() {}
    DEVICE(string set_dev_file_path) : dev_file_path(set_dev_file_path)
    {
        if (this->Dev_Init() == false)
        {
            cout << "设备打开异常！" << endl;
            exit(-1);
        }
    }
    ~DEVICE()
    {
        if (this->Dev_Free() == false)
        {
            cout << "设备关闭异常" << endl;
            exit(-1);
        }
    }
    virtual shared_ptr<ImageDisplay> create_display() = 0;
    virtual shared_ptr<TouchHandler> create_touch_handler() = 0;

    // 基类的公共属性
    string dev_file_path;
    int dev_fd;

    // 基类的公共行为
    bool Dev_Init(); // 打开设备文件
    bool Dev_Free(); // 关闭设备文件
};

// LCD类(派生类工厂类)
class LCD : public DEVICE
{
public:
    LCD() {}
    LCD(string set_dev_file_path) : DEVICE(set_dev_file_path)
    {
        if (this->Lcd_Star() == false)
        {
            cout << "获取屏幕信息失败" << endl;
            exit(-1);
        }
    }
    ~LCD()
    {
        // 解除映射
        munmap(this->mmap_ptr, this->screen_wide * this->screen_high);
    }

    shared_ptr<ImageDisplay> create_display() override
    {
        // 创建图片路径列表（你可以从目录读取，或手动添加）
        std::vector<std::string> imagePaths;
        imagePaths.push_back("/root/image/j1.jpg");
        imagePaths.push_back("/root/image/j2.jpg");
        imagePaths.push_back("/root/image/j3.jpg");
        imagePaths.push_back("/root/image/j4.jpg");
        imagePaths.push_back("/root/image/j5.jpg");
        imagePaths.push_back("/root/image/b1.bmp");
        imagePaths.push_back("/root/image/b2.bmp");
        imagePaths.push_back("/root/image/b3.bmp");
        imagePaths.push_back("/root/image/b4.bmp");

        // 传递给 Image 构造函数
        return make_shared<Image>(this->screen_wide, this->screen_high, this->mmap_ptr, imagePaths);
    }

    shared_ptr<TouchHandler> create_touch_handler()
    { // 这里必须写不然就是没有实现完基类的纯虚函数自己也会变成抽象类不能实例化抽象类，不能 new / make_shared
        return nullptr;
    }

    // 属性
    int screen_wide;
    int screen_high;
    char *mmap_ptr;

    // 行为获取屏幕长宽
    bool Lcd_Star(); // lcd运行启动：ioctl动态去获取LCD的分辨率 进行映射
};

// 触摸屏类(派生类工厂类)
class TOUCH : public DEVICE
{
public:
    TOUCH() {}
    TOUCH(string set_dev_file_path) : DEVICE(set_dev_file_path)
    {
        this->touch_max_x = 1024;
        this->touch_max_y = 600;
        this->touch_min_x = 0;
        this->touch_min_y = 0;
    }
    shared_ptr<ImageDisplay> create_display() override
    {
        return nullptr;
    }

    shared_ptr<TouchHandler> create_touch_handler()
    { // 这里必须写不然就是没有实现完基类的纯虚函数自己也会变成抽象类不能实例化抽象类，不能 new / make_shared
        return make_shared<Get_touch>(this->dev_fd);
    }

    // 属性
    int touch_max_x;
    int touch_max_y;
    int touch_min_x;
    int touch_min_y;
};

#endif